/*************************************************
 * ThinkJot V2
 * Author: Jeswin P. (jeswin@process64.com)
 * Website: http://www.process64.com/thinkjot/
 * This code is distributed under the terms of the
 * Apache License, Version 2.0.
 * **********************************************/

using System;
using System.Collections.Generic;
using System.Text;

using System.Web;

namespace ThinkJot.Core.Blogs
{
    public class ActivityStats
    {
        bool searchEngineSummaryLoaded = false;
        bool searchQueriesSummaryLoaded = false;
        bool requestedPagesSummaryLoaded = false;
        bool userAgentSummaryLoaded = false;
        bool referrersSummaryLoaded = false;

        #region Search Engine Summary
        public class SearchEngineSummaryItem
        {
            string searchEngineName;
            public string SearchEngineName
            {
                get { return searchEngineName; }
            }

            string searchEngineUrl;
            public string SearchEngineUrl
            {
                get { return searchEngineUrl; }
            }

            int count = 0;
            public int Count
            {
                get { return count; }
                set { count = value; }
            }

            public SearchEngineSummaryItem(string searchEngineName, string url)
            {
                this.searchEngineName = searchEngineName;
                this.searchEngineUrl = url;
            }
        }

        List<SearchEngineSummaryItem> searchEngineSummaryItems = new List<SearchEngineSummaryItem>();
        public List<SearchEngineSummaryItem> SearchEngineSummaryItems
        {
            get 
            {
                if (!searchEngineSummaryLoaded)
                {
                    CreateSearchEngineSummary();
                    searchEngineSummaryLoaded = true;
                }
                return searchEngineSummaryItems; 
            }
        }

        private void CreateSearchEngineSummary()
        {
            SearchEngineSummaryItem google = new SearchEngineSummaryItem("Google", "http://www.google.com");
            SearchEngineSummaryItem yahoo = new SearchEngineSummaryItem("Yahoo", "http://www.yahoo.com");
            SearchEngineSummaryItem live = new SearchEngineSummaryItem("Microsoft Live", "http://www.live.com");
            SearchEngineSummaryItem msn = new SearchEngineSummaryItem("Microsoft MSN", "http://search.msn.com");
            SearchEngineSummaryItem ask = new SearchEngineSummaryItem("Ask.com", "http://www.ask.com");
            SearchEngineSummaryItem others = new SearchEngineSummaryItem("Others", "");

            searchEngineSummaryItems.Add(google);
            searchEngineSummaryItems.Add(yahoo);
            searchEngineSummaryItems.Add(live);
            searchEngineSummaryItems.Add(msn);
            searchEngineSummaryItems.Add(ask);

            foreach (ActivityLogEntry entry in Entries)
            {
                try
                {
                    if (GetSearchEngine(entry.Referrer) == "Google")
                        google.Count++;

                    if (GetSearchEngine(entry.Referrer) == "Yahoo")
                        yahoo.Count++;

                    if (GetSearchEngine(entry.Referrer) == "Microsoft Live")
                        live.Count++;

                    if (GetSearchEngine(entry.Referrer) == "Microsoft MSN")
                        msn.Count++;

                    if (GetSearchEngine(entry.Referrer) == "Ask.com")
                        ask.Count++;

                    if (GetSearchEngine(entry.Referrer) == "Other")
                        others.Count++;
                }
                catch
                {
                    //Don't log. We will fill the log.
                }
            }
        }
        #endregion

        #region Search Queries Summary

        public class SearchQueriesSummaryItem
        {
            string searchEngine;
            public string SearchEngine
            {
                get { return searchEngine; }
                set { searchEngine = value; }
            }

            string referrer;
            public string Referrer
            {
                get { return referrer; }
                set { referrer = value; }
            }

            string query;
            public string Query
            {
                get { return query; }
                set { query = value; }
            }

            int count;
            public int Count
            {
                get { return count; }
                set { count = value; }
            }
        }

        List<SearchQueriesSummaryItem> searchQueriesSummaryItems = new List<SearchQueriesSummaryItem>();
        public List<SearchQueriesSummaryItem> SearchQueriesSummaryItems
        {
            get 
            {
                if (!searchQueriesSummaryLoaded)
                {
                    CreateSearchQueriesSummary();
                    searchQueriesSummaryLoaded = true;
                }
                return searchQueriesSummaryItems; 
            }
        }

        private void CreateSearchQueriesSummary()
        {            
            foreach (ActivityLogEntry entry in Entries)
            {
                try
                {
                    //searchQ[1] = engineName, searchQ[2] = query
                    string[] searchQ = GetSearchEngineAndQuery(entry.Referrer);

                    bool isInList = false;
                    if (!string.IsNullOrEmpty(searchQ[0]) && !string.IsNullOrEmpty(searchQ[1]))
                    {
                        //see if it is already added
                        //somewhat expensive.
                        foreach (SearchQueriesSummaryItem sqsItem in searchQueriesSummaryItems)
                        {
                            if (sqsItem.SearchEngine == searchQ[0] && sqsItem.Query == searchQ[1])
                            {
                                sqsItem.Count++;
                                isInList = true;
                            }
                        }
                        if (!isInList)
                        {
                            //not found... so lets add a new entry.                
                            SearchQueriesSummaryItem item = new SearchQueriesSummaryItem();
                            item.SearchEngine = searchQ[0];
                            item.Referrer = entry.Referrer;
                            item.Query = searchQ[1];
                            item.Count = 1;
                            searchQueriesSummaryItems.Add(item);
                        }
                    }
                }
                catch
                {
                    //dont log.
                }
            }

            searchQueriesSummaryItems.Sort(delegate(SearchQueriesSummaryItem item1, SearchQueriesSummaryItem item2)
            {
                if (item1.Count < item2.Count)
                    return 1;
                if (item1.Count > item2.Count)
                    return -1;
                return 0;
            });
        }

        #endregion

        #region Requested Pages Summary

        public class RequestedPagesSummaryItem
        {
            string pageUrl;
            public string PageUrl
            {
                get { return pageUrl; }
                set { pageUrl = value; }
            }

            int count;
            public int Count
            {
                get { return count; }
                set { count = value; }
            }
        }

        List<RequestedPagesSummaryItem> requestedPagesSummaryItems = new List<RequestedPagesSummaryItem>();
        public List<RequestedPagesSummaryItem> RequestedPagesSummaryItems
        {
            get 
            {
                if (!requestedPagesSummaryLoaded)
                {
                    CreateRequestedPagesSummary();
                    requestedPagesSummaryLoaded = true;
                }
                return requestedPagesSummaryItems; 
            }
        }

        private void CreateRequestedPagesSummary()
        {
            Dictionary<string, int> pagesAndCount = new Dictionary<string, int>();
            foreach (ActivityLogEntry entry in Entries)
            {
                try
                {
                    if (pagesAndCount.ContainsKey(entry.RawUrl))
                        pagesAndCount[entry.RawUrl]++;
                    else
                        pagesAndCount[entry.RawUrl] = 1;
                }
                catch
                {
                    //dont log....
                }
            }
            foreach (KeyValuePair<string, int> pair in pagesAndCount)
            {
                RequestedPagesSummaryItem item = new RequestedPagesSummaryItem();
                item.PageUrl = pair.Key;
                item.Count = pair.Value;
                requestedPagesSummaryItems.Add(item);
            }

            requestedPagesSummaryItems.Sort(delegate(RequestedPagesSummaryItem item1, RequestedPagesSummaryItem item2)
            {
                if (item1.Count < item2.Count)
                    return 1;
                if (item1.Count > item2.Count)
                    return -1;
                return 0;
            });
        }
        
        #endregion

        #region User Agent Summary

        public class UserAgentSummaryItem
        {
            string userAgent;
            public string UserAgent
            {
                get { return userAgent; }
                set { userAgent = value; }
            }

            int count;
            public int Count
            {
                get { return count; }
                set { count = value; }
            }
        }

        List<UserAgentSummaryItem> userAgentSummaryItems = new List<UserAgentSummaryItem>();
        public List<UserAgentSummaryItem> UserAgentSummaryItems
        {
            get 
            {
                if (!userAgentSummaryLoaded)
                {
                    CreateUserAgentSummary();
                    userAgentSummaryLoaded = true;
                }
                return userAgentSummaryItems; 
            }
        }

        private void CreateUserAgentSummary()
        {
            Dictionary<string, int> agentsAndCount = new Dictionary<string, int>();
            foreach (ActivityLogEntry entry in Entries)
            {
                try
                {
                    if (agentsAndCount.ContainsKey(entry.UserAgent))
                        agentsAndCount[entry.UserAgent]++;
                    else
                        agentsAndCount[entry.UserAgent] = 1;
                }
                catch
                {
                    //dont log....
                }
            }
            foreach (KeyValuePair<string, int> pair in agentsAndCount)
            {
                UserAgentSummaryItem item = new UserAgentSummaryItem();
                item.UserAgent = pair.Key;
                item.Count = pair.Value;
                userAgentSummaryItems.Add(item);
            }
            userAgentSummaryItems.Sort(delegate(UserAgentSummaryItem item1, UserAgentSummaryItem item2)
            {
                if (item1.Count < item2.Count)
                    return 1;
                if (item1.Count > item2.Count)
                    return -1;
                return 0;
            });
        }
        #endregion

        #region Referrers Summary

        public class ReferrersSummaryItem
        {
            string referringUrl;
            public string ReferringUrl
            {
                get { return referringUrl; }
                set { referringUrl = value; }
            }

            List<string> insiteUrls = new List<string>();
            public List<string> InsiteUrls
            {
                get { return insiteUrls; }
                set { insiteUrls = value; }
            }

            int count;
            public int Count
            {
                get { return count; }
                set { count = value; }
            }
        }

        List<ReferrersSummaryItem> referrersSummaryItems = new List<ReferrersSummaryItem>();
        public List<ReferrersSummaryItem> ReferrersSummaryItems
        {
            get 
            {
                if (!referrersSummaryLoaded)
                {
                    CreateReferrersSummary();
                    referrersSummaryLoaded = true;
                }
                return referrersSummaryItems; 
            }
        }

        private void CreateReferrersSummary()
        {
            Dictionary<string, int> referrersAndCount = new Dictionary<string, int>();
            foreach (ActivityLogEntry entry in Entries)
            {
                bool isInList = false;
                try
                {
                    foreach (ReferrersSummaryItem item in referrersSummaryItems)
                    {
                        if (item.ReferringUrl == entry.Referrer)
                        {
                            if (!item.InsiteUrls.Contains(entry.RawUrl))
                                item.InsiteUrls.Add(entry.RawUrl);
                            item.Count++;
                            isInList = true;
                        }
                    }
                    if (!isInList)
                    {
                        ReferrersSummaryItem item = new ReferrersSummaryItem();
                        item.ReferringUrl = entry.Referrer;
                        item.InsiteUrls.Add(entry.RawUrl);
                        item.Count = 1;
                        referrersSummaryItems.Add(item);
                    }
                }
                catch
                {
                    //dont log....
                }
            }
            referrersSummaryItems.Sort(delegate(ReferrersSummaryItem item1, ReferrersSummaryItem item2)
            {
                if (item1.Count < item2.Count)
                    return 1;
                if (item1.Count > item2.Count)
                    return -1;
                return 0;
            });
        }

        #endregion

        List<ActivityLogEntry> entries = new List<ActivityLogEntry>();
        public List<ActivityLogEntry> Entries
        {
            get { return entries; }
        }

        public ActivityStats(List<ActivityLogEntry> entries)
        {
            this.entries = entries;
        }

        private static string GetSearchEngine(string referrer)
        {
            Uri uri = new Uri(referrer);

            if (uri.Host.Contains("google") && uri.Query.Contains("q="))
                return "Google";

            if (uri.Host.Contains("yahoo") && uri.Query.Contains("p="))
                return "Yahoo";

            if (uri.Host.Contains("live") && uri.Query.Contains("q="))
                return "Microsoft Live";

            if (uri.Host.Contains("msn") && uri.Query.Contains("q="))
                return "Microsoft MSN";

            if (uri.Host.Contains("ask") && uri.Query.Contains("q="))
                return "Ask.com";

            //We are using only q here; ignoring p
            //Some google searches can come from IP Addresses, ie from Google Testing Servers
            if (uri.Query.Contains("q=")) 
                return "Other";
            return "";
        }

        private static string[] GetSearchEngineAndQuery(string referrer)
        {            
            string searchEngine = GetSearchEngine(referrer);
            if (!string.IsNullOrEmpty(searchEngine))
            {
                Uri uri = new Uri(referrer);
                string query = uri.Query;
                if (query.StartsWith("?"))
                    query = query.Substring(1);
                string[] querystringParams = query.Split('&');
                foreach (string qsParam in querystringParams)
                {
                    string[] paramNameVal = qsParam.Split('=');
                    if (searchEngine != "Yahoo")
                    {
                        if (paramNameVal[0] == "q" && !string.IsNullOrEmpty(paramNameVal[1]))
                            return new string[] { searchEngine, HttpUtility.UrlDecode(paramNameVal[1]) };
                    }
                    //Yahoo uses 'p'
                    else
                    {
                        if (paramNameVal[0] == "p" && !string.IsNullOrEmpty(paramNameVal[1]))
                            return new string[] { searchEngine, HttpUtility.UrlDecode(paramNameVal[1]) };
                    }
                }
            }
            return new string[] { "", "" };
        }
    }
}
